<?php

namespace App\Http\Controllers\H5;

use App\Common\SDK\Domain\FenZhangTong;
use App\Common\Utils\Helper;
use App\Http\Controllers\Controller;
use App\Jobs\TopUpActiveQueryResultsJob;
use App\Models\Agent;
use App\Models\AgentRevenue;
use App\Models\AgentTopUpOrder;
use App\Models\AgentXiamenBankAccount;
use App\Models\ModelHasPaymentOrder;
use App\Models\PaymentChannelFztcashier;
use App\Models\PaymentChannelFztwx;
use App\Models\PaymentChannelFztumswx;   //yang
use App\Models\AgentWithdrawAccountReg;   //yang
use App\Models\PaymentOrder;
use App\Services\PaymentService;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
use Symfony\Component\HttpKernel\Exception\HttpException;

class WalletController extends Controller
{
    /**
     * 代理商充值
     */
    public function topUp(Request $request)
    {
        $this->validate($request,
            [
                'amount' => [
                    'required',
                    'integer',
                    'min:20100',
                    function ($attribute, $value, $fail) {
                        if (!(((int) ($value / 100)) % 10 > 0)) {
                            $fail('充值金额个位数(元)不能为零');
                        }
                    }
                ],
                'channel' => 'required|in:' . implode(',', [PaymentOrder::PAYMENT_CHANNEL_FZT_WX, PaymentOrder::PAYMENT_CHANNEL_FZT_CA, PaymentOrder::PAYMENT_CHANNEL_SD_WX]),
                'openid' => 'required_if:channel,' . PaymentOrder::PAYMENT_CHANNEL_FZT_WX,
            ], [
                'amount.required' => '缺失充值金额',
                'amount.integer' => '充值金额不合法(必须为数字类型)',
                'amount.min' => '充值金额不得少于201元',
                'channel.required' => '缺失支付渠道',
                'channel.in' => '支付渠道不存在',
                'openid.required' => '缺失微信用户标识',
                'openid.required_if' => '缺失微信用户标识,请前往首页刷新或者尝试重新登陆',
            ]
        );

        $reqData = $request->all();

        try {
            //默认微信通道
            $default_weixin_channel_code = env('WEIXIN_CHANNEL_CODE_ID');
            if (!empty($default_weixin_channel_code) && (int) $reqData['channel'] === PaymentOrder::PAYMENT_CHANNEL_FZT_WX){
                $reqData['channel'] =  $default_weixin_channel_code; // 赋值配置项
            }

            //测试某一用户OPENID指定特殊通道  15058363570的账号
            // if ($reqData['openid']== 'oGByR1gMFb8Nq4swUe9f8yKjLvlo'){
            //     $reqData['channel'] =  PaymentOrder::PAYMENT_CHANNEL_UMS_WX; //银联商务微信支付 4
            //     $reqData['amount'] =  10; 
            // }

            // 充值表的订单号
            if ((int) $reqData['channel'] === PaymentOrder::PAYMENT_CHANNEL_UMS_WX ){
                //如果chianums微信支付时 银商分配4位数开关 长度28位
                $businessOrderId = env('CHINA_UMS_MSG_SRC_ID') . PaymentOrder::ORDER_ID_PREFIX[PaymentOrder::ORDER_TYPE_TOP_UP] . Carbon::now()->format('YmdHisu') . Str::random(2);
            }else{
                $businessOrderId = PaymentOrder::ORDER_ID_PREFIX[PaymentOrder::ORDER_TYPE_TOP_UP] . Carbon::now()->format('YmdHisu') . Str::random(10);
            }
           
            // 用户充值订单
            /** @var Agent $user */
            $user = \Auth::user();
            /** @var AgentTopUpOrder $topUpOrder */
            $topUpOrder = $user->topUpOrder()->create(['order_id' => $businessOrderId, 'amount' => $reqData['amount']]);

            // 简单点 .. 三个 if 写在这一个 function 里
            if ((int) $reqData['channel'] === PaymentOrder::PAYMENT_CHANNEL_FZT_WX) {
                // 收银台订单
                [$paymentOrder, $channelOrder] = (new PaymentService())->defray(array_merge(
                    $reqData,
                    [
                        'out_trade_no' => $businessOrderId, // 业务订单号
                        'pay_type' => PaymentChannelFztwx::WECHAT_PAY_TYPE_JSAPI,
                        'client_id' => $request->ip(),
                        'subject' => '代理商账户余额充值',
                        'body' => '代理商账户余额充值',
                        'openid' => $reqData['openid'],
                        'app_id' => env('WECHAT_OFFICIAL_ACCOUNT_APPID'),
                        'notify_url' => url('api/finance/notify/fzt_wechat'),
                        'return_url' => url('h5/my/wallet/top-up?payment=complete'),
                    ]
                ));
                // 充值订单对应收银台订单
                $topUpOrder->paymentOrders()->sync([$paymentOrder['id'] => ['type' => ModelHasPaymentOrder::TYPE_BUSINESS_ORDER]]);

                // 定时查询支付结果
                dispatch((new TopUpActiveQueryResultsJob($businessOrderId))->delay(Carbon::now()->addMinutes(5)));

                // 处理下 payInfo
                $payInfo = json_decode('{' . $channelOrder['payInfo'] . '}', true); // 返回的 payInfo 是个 json 字符串少了两边的 {}, 补上后 decode
                return $this->response->created(null, [
                    'timestamp' => $payInfo['timeStamp'],
                    'nonceStr' => $payInfo['nonceStr'],
                    'package' => $payInfo['package'],
                    'signType' => $payInfo['signType'],
                    'paySign' => $payInfo['paySign'],
                ]);
            } elseif ((int) $reqData['channel'] === PaymentOrder::PAYMENT_CHANNEL_FZT_CA) {
                // 收银台订单
                [$paymentOrder, $channelOrder] = (new PaymentService())->defray(array_merge(
                    $reqData,
                    [
                        'out_trade_no' => $businessOrderId, // 业务订单号
                        'pay_method' => PaymentChannelFztcashier::PAY_METHOD_QUICK_PAYMENT,
                        'subject' => '代理商账户余额充值',
                        'body' => '代理商账户余额充值',
                        'notify_url' => url('api/finance/notify/fzt_cashier'),
                        'return_url' => url('h5/my'),
                    ]
                ));
                // 充值订单对应收银台订单
                $topUpOrder->paymentOrders()->sync([$paymentOrder['id'] => ['type' => ModelHasPaymentOrder::TYPE_BUSINESS_ORDER]]);

                // 定时查询支付结果
                dispatch((new TopUpActiveQueryResultsJob($businessOrderId, 'cashier'))->delay(Carbon::now()->addMinutes(5)));

                return $this->response->created(null, [
                    'ret_url' => $channelOrder['retUrl']
                ]);
            } elseif ((int) $reqData['channel'] === PaymentOrder::PAYMENT_CHANNEL_SD_WX) {
                // 收银台订单
                [$paymentOrder, $channelOrder] = (new PaymentService())->defray(array_merge(
                    $reqData,
                    [
                        'out_trade_no' => $businessOrderId, // 业务订单号
                        'subject' => '代理商账户余额充值',
                        'body' => '代理商账户余额充值',
                        'openid' => $reqData['openid'],
                        'app_id' => env('WECHAT_OFFICIAL_ACCOUNT_APPID'),
                        'notify_url' => url('api/finance/notify/sd_wechat'),
                        'ip' => $request->getClientIp(),
                    ]
                ));
                // 充值订单对应收银台订单
                $topUpOrder->paymentOrders()->sync([$paymentOrder['id'] => ['type' => ModelHasPaymentOrder::TYPE_BUSINESS_ORDER]]);

                // 定时查询支付结果
                dispatch((new TopUpActiveQueryResultsJob($businessOrderId, 'sdwx'))->delay(Carbon::now()->addMinutes(5)));

                // 处理下 payInfo
                return $this->response->created(null, [
                    'timestamp' => $channelOrder['timeStamp'],
                    'nonceStr' => $channelOrder['nonceStr'],
                    'package' => $channelOrder['package'],
                    'signType' => $channelOrder['signType'],
                    'paySign' => $channelOrder['paySign'],
                ]);
            } elseif ((int) $reqData['channel'] === PaymentOrder::PAYMENT_CHANNEL_UMS_WX) {
                // 银联商务
                [$paymentOrder, $channelOrder] = (new PaymentService())->defray(array_merge(
                    $reqData,
                    [
                        'out_trade_no' => $businessOrderId, // 业务订单号
                        'subject' => '代理商账户余额充值',
                        'body' => '代理商账户余额充值',
                        'notify_url' => url('api/finance/notify/ums_wechat'),
                        'return_url' => url('api/finance/ums_return?sn=' . $businessOrderId . '&amount=' . $reqData['amount']),
                    ]
                ));
                
                // 充值订单对应收银台订单
                $topUpOrder->paymentOrders()->sync([$paymentOrder['id'] => ['type' => ModelHasPaymentOrder::TYPE_BUSINESS_ORDER]]);

                // 定时查询支付结果
                dispatch((new TopUpActiveQueryResultsJob($businessOrderId, 'umswx'))->delay(Carbon::now()->addMinutes(5)));

                // 处理下 payInfo
                return $this->response->created(null, [
                    'timestamp' => $channelOrder['timeStamp'],
                    'nonceStr' => $channelOrder['nonceStr'],
                    'package' => $channelOrder['package'],
                    'signType' => $channelOrder['signType'],
                    'paySign' => $channelOrder['paySign'],
                    'appId' => $channelOrder['appId'],
                ]);
                
            }
        } catch (HttpException $e) {
            \Log::error(sprintf('发起充值发生错误: %s (%s [%d])', $e->getMessage(), $e->getFile(), $e->getLine()));
            $this->response->errorBadRequest($e->getMessage());
        }

        throw new HttpException(400, '不存在的支付渠道');
    }

    /**
     * 收支明细
     */
    public function revenueList(Request $request)
    {
        return $this->response->array(
            Helper::dealWithNotCompatibleSimplePaginate(
                AgentRevenue::query()
                    ->without(['agent'])
                    ->with(['source'])
                    ->where('agent_id', $this->user['id'])
                    ->when($request->get('type'), function (Builder $builder, $type) {
                        $builder->where('type', $type);
                    })
                    ->when($request->get('revenues_type'), function (Builder $builder, $revenuesType) {
                        $builder->where('revenues_type', $revenuesType);
                    })
                    ->when($request->get('created_at_begin'), function (Builder $builder, $createdAtBegin) {
                        $builder->where('created_at', '>=', $createdAtBegin);
                    })
                    ->when($request->get('created_at_end'), function (Builder $builder, $createdAtEnd) {
                        $builder->where('created_at', '<=', Carbon::parse($createdAtEnd)->endOfDay());
                    })
                    ->orderByDesc('id')
                    ->simplePaginate()
            )
        );
    }

    /**
     * 划拨余额给另外个代理商
     * @param Request $request
     */
    public function transferBalance(Request $request)
    {
        \Cache::lock('agent_transfer_balance_block' . $this->user['id'], 10)->block(10, function () use ($request) {
            $agent = Agent::query()->findOrFail($this->user['id']);

            $this->validate($request, [
                'amount_allocated' => ['required', 'integer', 'min:1', 'lte:' . ($agent['balance'] + $agent['unextractable_balance'])],
                'agent_id' => ['required', 'not_in:' . $agent['id']]
            ], [
                'amount_allocated.required' => '缺失划拨金额',
                'amount_allocated.integer' => '划拨金额不合法',
                'amount_allocated.min' => '划拨金额最少一分钱',
                'amount_allocated.lte' => '余额不足,划拨失败!',
                'agent_id.required' => '缺失代理商ID',
                'agent_id.not_in' => '不能给自己划拨'
            ]);

            \DB::transaction(function () use ($request, $agent) {
                $targetAgent = Agent::query()->findOrFail($request->get('agent_id', ''));
                // 只给自己团队的划转
                $targetAgentParentPathId = explode('-', $targetAgent['parent_path_id']);
                if (!in_array((string) $agent['id'], $targetAgentParentPathId, true)) {
                    abort(400, '仅限于团队内，上级给下级划拨');
                }

                // 先转不可提
                $amountAllocated = $request->get('amount_allocated');
                $agentUnextractableBalance = ($agent['unextractable_balance'] < 0 ? 0 : $agent['unextractable_balance']); // 划拨用户的不可提现金额, 这里修复不可提现为负数时,造成的多扣款情况
                if ($agentUnextractableBalance < $amountAllocated) {
                    // 这里要先加对方的, 如果先操作自己的话, increment 操作会修改 model 对象值
                    /** @var AgentRevenue|null $targetAgentBalanceRevenues */
                    $targetAgentBalanceRevenues = $targetAgent->incrementOrDecrementBalance($amountAllocated - $agentUnextractableBalance, AgentRevenue::TYPE_TRANSFER);
                    /** @var AgentRevenue|null $targetAgentUnextractableBalanceRevenues */
                    $targetAgentUnextractableBalanceRevenues = $targetAgent->incrementOrDecrementUnextractableBalance($agentUnextractableBalance, AgentRevenue::TYPE_TRANSFER);

                    $agentBalanceRevenues = $agent->incrementOrDecrementBalance($amountAllocated - $agentUnextractableBalance, AgentRevenue::TYPE_TRANSFER, $targetAgentBalanceRevenues, 'decrement');
                    $agentBalanceRevenues && $agentBalanceRevenues->agentRevenues()->save($targetAgentBalanceRevenues); // 绑定关系
                    $agentUnextractableBalanceRevenues = $agent->incrementOrDecrementUnextractableBalance($agentUnextractableBalance, AgentRevenue::TYPE_TRANSFER, $targetAgentUnextractableBalanceRevenues, 'decrement');
                    $agentUnextractableBalanceRevenues && $agentUnextractableBalanceRevenues->agentRevenues()->save($targetAgentUnextractableBalanceRevenues); // 绑定关系
                } else {
                    // 同上, 这里得先操作对方的
                    /** @var AgentRevenue|null $targetAgentBalanceRevenues */
                    $targetAgentBalanceRevenues = $targetAgent->incrementOrDecrementUnextractableBalance($amountAllocated, AgentRevenue::TYPE_TRANSFER);

                    $agentBalanceRevenues = $agent->incrementOrDecrementUnextractableBalance($amountAllocated, AgentRevenue::TYPE_TRANSFER, $targetAgentBalanceRevenues, 'decrement');
                    $agentBalanceRevenues && $agentBalanceRevenues->agentRevenues()->save($targetAgentBalanceRevenues); // 绑定关系
                }
            });
        });

        return $this->response->noContent();
    }

    /**
     * 提现
     * @param Request $request
     * @return \Dingo\Api\Http\Response
     * @throws \Illuminate\Validation\ValidationException
     * @throws \Throwable
     */
    public function withdraw(Request $request)
    {
        $this->validate($request, [
            'amount' => ['required', 'integer', 'min:5000', 'lte:' . $this->user['balance']],
            'cardholder_name' => ['required'],
            'bank_card_account' => ['required'],
            'bank_name' => ['required'],
            'cardholder_id_number' => ['required'], 
            'bank_phone' => ['required', 'regex:/^(?:\+?86)?1(?:3\d{3}|5[^4\D]\d{2}|8\d{3}|7(?:[235-8]\d{2}|4(?:0\d|1[0-2]|9\d))|9[0-35-9]\d{2}|66\d{2})\d{6}$/'],

        ], [
            'amount.required' => '提现金额不得为空',
            'amount.integer' => '提现金额不合法',
            'amount.min' => '最小提现金额为 50 元',
            'amount.lte' => '可提现余额不足',
            'cardholder_name.required' => '持卡人姓名不得为空',
            'bank_card_account.required' => '银行卡号不得为空',
            'bank_name.required' => '银行姓名不得为空',
            'cardholder_id_number.required' => '持卡人身份证号不得为空',
            'bank_phone.required' => '预留手机号不得为空',
            'bank_phone.regex' => '预留手机号填写不正确',
        ]);

        $withdrawRecord = null;
        try {
            \DB::beginTransaction();

            $card_reg_status = env('WITHDRAW_CARD_REG_STATUS',false);
            if ($card_reg_status){
                $withdraw_channel_code = env('WITHDRAW_CHANNEL_CODE','');
            
                $accountData = [
                    'cardholder_name' => $request->get('cardholder_name'),
                    'cardholder_id_number' => $request->get('cardholder_id_number'),
                    'bank_name' => $request->get('bank_name'),
                    'bank_card_account' => $request->get('bank_card_account'),
                    'bank_phone' => $request->get('bank_phone'),
                    'channel_code'=> $withdraw_channel_code,
                ];
                //提现卡是否已经注册
                $isExist = AgentWithdrawAccountReg::query()
                    ->where($accountData)
                    ->where('channel_code',$withdraw_channel_code)
                    ->whereIn('status',[AgentWithdrawAccountReg::STATUS_PENDING,AgentWithdrawAccountReg::STATUS_SUCCESS])
                    ->select('id')->exists();

                if (!$isExist){
                    //注册提现卡
                    $regRes = (new PaymentService())->withdrawAccountReg($accountData,$withdraw_channel_code);
                    if ($regRes['code'] != '0000'){
                        throw new HttpException(400, $regRes['msg']);
                    }

                    if (is_array($regRes['params'])){
                        //添加提现卡注册数据
                        $accountRes = $this->user->withdrawAccountReg()->create(array_merge($regRes['params'],[
                            'status' => 1,
                        ]));
                    }
                }  
            }

            $amount = $request->get('amount');
            $withdrawRecord = $this->user->withdrawRecords()->create([
                'withdrawal_amount' => $amount,
                'cardholder_name' => $request->get('cardholder_name'),
                'cardholder_id_number' => $request->get('cardholder_id_number'),
                'bank_name' => $request->get('bank_name'),
                'bank_card_account' => $request->get('bank_card_account'),
                'bank_phone' => $request->get('bank_phone'),
            ]);

            // 挪动账户余额 => 提现金额
            $this->user->incrementOrDecrementBalance($amount, AgentRevenue::TYPE_EXTRACT, $withdrawRecord, 'decrement');
            $this->user->incrementOrDecrementAmountInWithdrawal($amount);

            \DB::commit();
        } catch (\Exception $e) {
            \DB::rollBack();
            $this->response->errorBadRequest($e->getMessage());
        }

        return $this->response->created(null, $withdrawRecord);
    }
}
